const { src, dest, parallel, series, watch } = require("gulp");

// 💡 使用插件代替逐个引入 gulp 插件的方式
const loaderPlugin = require("gulp-load-plugins");
const plugin = loaderPlugin();
// const sass = require("gulp-sass");
// const babel = require("gulp-babel");
// const swig = require("gulp-swig");
// const imagemin = require("gulp-imagemin");

const del = require("del");
const browserSync = require("browser-sync");
const bs = browserSync.create();

/*
 * 1. 编译 css 样式
 * 插件: gulp-sass
 * */
const style = () => {
  // base: 保留src后的路径
  return (
    src("src/assets/styles/*.scss", { base: "src" })
      // outputStyle 格式化输出的文件
      .pipe(plugin.sass({ outputStyle: "expanded" }))
      .pipe(dest("temp"))
  );
};

/*
 * 2. 编译 script 模块
 * 插件: gulp-babel @babel/core @babel/preset-env
 * */
const script = () => {
  return (
    src("src/assets/scripts/*.js", { base: "src" })
      // babel 只是一个编译的平台本身不具有转换的功能需要配置插件使用
      .pipe(plugin.babel({ presets: ["@babel/preset-env"] }))
      .pipe(dest("temp"))
  );
};

/*
 * 3. 编译 html 文件
 * 插件: gulp-swig
 * */
const page = () => {
  return src("src/*.html", { base: "src" })
    .pipe(plugin.swig({ data: require("./data.js") }))
    .pipe(dest("temp"));
};

/*
 * 4. 打包静态文件
 * 插件: gulp-imagemin
 * */
const image = () => {
  return src("src/assets/images/**", { base: "src" })
    .pipe(plugin.imagemin())
    .pipe(dest("dist"));
};
const font = () => {
  return src("src/assets/fonts/**", { base: "src" })
    .pipe(plugin.imagemin())
    .pipe(dest("dist"));
};
const extra = () => {
  return src("public/**", { base: "public" })
    .pipe(plugin.imagemin())
    .pipe(dest("dist"));
};

/*
 * 5. 每次打包前删除dist文件
 * 插件: del (是一个 node 模块, 不属于 gulp 的插件)
 * */
const clean = () => {
  return del(["dist", "temp"]);
};

/*
 * 6. 设置浏览器服务
 * 插件: browser-sync
 * */
const serve = () => {
  // 开发时监听文件的变化并执行编译 实现热更新
  watch("src/assets/styles/*.scss", style);
  watch("src/assets/scripts/*.js", script);
  watch("src/*.html", page);
  // 开发时静态资源变化时重新刷新页面
  watch(
    ["src/assets/images/**", "src/assets/fonts/**", "public/**"],
    bs.reload
  );
  // 开发的过程中不需要打包静态资源, 这样可以提高编译的效率
  // watch("src/assets/images/**", image);
  // watch("src/assets/fonts/**", font);
  // watch("public/**", extra);

  bs.init({
    notify: false, // 禁用浏览器右上角的提示
    port: 3000,
    files: "dist/**", // 监听编译后的文件
    server: {
      // 数组: 浏览器请求中, 第一个文件请求不到资源时, 会查找下一个文件的资源
      // 开发的过程中省略静态资源的打包环节, 提高编译的效率
      baseDir: ["temp", "src", "public"],
      // 开发时不会打包项目依赖
      // 让 script 的引用有限使用项目的依赖 在使用 dist 中的资源
      routes: {
        "/node_modules": "node_modules",
      },
    },
  });
};

/*
 * 7.处理引用的依赖和文件的压缩
 * 插件: gulp-useref gulp-if gulp-uglify gulp-clean-css gulp-htmlmin
 * 配合 html 中的构建注释一起使用 <!-- build:css assets/styles/vendor.css --><!-- endbuild -->
 * */
const useRef = () => {
  return (
    // 之所以需要把编译的文件放到 temp, 而不直接输出到 dist 中, 因为同时对 dist 文件进行读写会造成冲突
    src("temp/*.html", { base: "temp" })
	    // 获取所有 html，pipe 到 plugins.useref这个转换流中，useref 会处理其中的构建注释
	    // searchPath 中指明在什么地方去找构建注释中的文件，'.' 表示根目录
      .pipe(plugin.useref({ searchPath: ["temp", "."] }))
      // 压缩文件
      .pipe(plugin.if(/\.js$/, plugin.uglify()))
      .pipe(plugin.if(/\.css$/, plugin.cleanCss()))
      .pipe(
        plugin.if(
          /\.html$/,
          plugin.htmlmin({
            collapseWhitespace: true,
            mimifyCSS: true,
            mimifyJS: true,
          })
        )
      )
      .pipe(dest("dist"))
  );
};

// 需要编译的文件
const compile = parallel(style, script, page);

// 生产环境时还需要打包额外的静态文件
const build = series(
  clean,
  parallel(series(compile, useRef), image, font, extra)
);

// 开发环境时编译的任务
const dev = series(clean, parallel(compile, serve));

/*
 * 8. 在 package.json 中定义script */
module.exports = {
  clean,
  build,
  dev,
};
